﻿using System;
using System.Collections.ObjectModel;

namespace Microsoft.Xna.Framework
{
    /// <summary>
    /// A collection of game components.
    /// </summary>
	public sealed class GameComponentCollection : Collection<IGameComponent>
    {
        //Since our DrawOrder & UpdateOrder are independent, if we want to 
        //perform updates and draws in the correct order, we have two options
        // 1) Sort every cycle (slower, but simpler)
		// 2) Maintain Two Lists (a bit more complex and bug-prone, but more efficient)

		#region Events
		/// <summary>
		/// Raised when a component is added to the GameComponentCollection.
		/// </summary>
		public event EventHandler<GameComponentCollectionEventArgs> ComponentAdded;

		/// <summary>
		/// Raised when a component is removed from the GameComponentCollection.
		/// </summary>
		public event EventHandler<GameComponentCollectionEventArgs> ComponentRemoved;
		#endregion

		#region Protected Methods
		protected override void ClearItems()
		{
			for (int i = 0; i < base.Count; i++)
			{
				EventHandler<GameComponentCollectionEventArgs> componentRemovedHandler = this.ComponentRemoved;
				if (componentRemovedHandler != null)
				{
					componentRemovedHandler(this, new GameComponentCollectionEventArgs(base[i]));
				}
			}
			base.ClearItems();
		}

		protected override void InsertItem(int index, IGameComponent item)
		{
			if (base.IndexOf(item) != -1)
			{
				throw new ArgumentException(FrameworkResources.CannotAddSameComponentMultipleTimes);
			}
			base.InsertItem(index, item);
			if (item != null)
			{
				EventHandler<GameComponentCollectionEventArgs> componentAddedHandler = this.ComponentAdded;
				if (componentAddedHandler != null)
				{
					componentAddedHandler(this, new GameComponentCollectionEventArgs(item));
				}
			}
		}

		protected override void RemoveItem(int index)
		{
			IGameComponent gameComponent = base[index];
			base.RemoveItem(index);
			if (gameComponent != null)
			{
				EventHandler<GameComponentCollectionEventArgs> componentRemovedHandler = this.ComponentRemoved;
				if (componentRemovedHandler != null)
				{
					componentRemovedHandler(this, new GameComponentCollectionEventArgs(gameComponent));
				}
			}
		}

		protected override void SetItem(int index, IGameComponent item)
		{
			throw new NotSupportedException(FrameworkResources.CannotSetItemsIntoGameComponentCollection);
		}
		#endregion
	}

    /// <summary>
    /// Arguments used with events from the GameComponentCollection.
    /// </summary>
    public class GameComponentCollectionEventArgs : EventArgs
    {
        /// <summary>
        /// Creates a new instance of GameComponentCollectionEventArgs.
        /// </summary>
        /// <param name="gameComponent">The game component affected by the event.</param>
        public GameComponentCollectionEventArgs(IGameComponent gameComponent)
        {
            this.GameComponent = gameComponent;
        }

        /// <summary>
        /// The game component affected by the event.
        /// </summary>
        public IGameComponent GameComponent { get; private set; }
    }
}
